/**
 * @author liangxi
 * @since 2024/3/20
 */

#ifndef LOGGER_LOGGER_H
#define LOGGER_LOGGER_H

#include <string_view>
#include <string>
#include <memory>
#include <iostream>
#include <source_location>
#include <deque>
#include <condition_variable>
#include "Component/Log.h"
#include "Behavior/Write/Write.h"

class Logger {
public:
    virtual ~Logger() = default;

    //通过静态局部变量 实现线程安全的单例模式
    static Logger &getIntance() {
        static Logger instance;
        return instance;
    }

    /**
     * 异步打印日志
     * @param content 需要打印的内容
     * @param level 日志类型
     * @param out 输出方式
     * @param path 输出路径/在Console模式下可忽略
     * @param location 用于记录文件名和行号
     */
    virtual void asyncLog(std::string_view content, Log::LogLevel level = Log::LogLevel::Debug,
                          Log::Output out = Log::Output::Console, std::string_view path = "./AppLog/",
                          const std::source_location &location = std::source_location::current());

    /**
     * 同步打印日志
     * @param content
     * @param level
     * @param out
     * @param path
     * @param location
     */
    virtual void syncLog(std::string_view content, Log::LogLevel level = Log::LogLevel::Debug,
                         Log::Output out = Log::Output::Console, std::string_view path = "./AppLog/",
                         const std::source_location &location = std::source_location::current());


    /**
     * 启动日志线程
     * 在异步输出日志之前调用
     */
    inline void startLogThread();

    /**
     * 停止日志线程
     */
    inline void stopLogThread();


private:

    Logger() = default;

    void setIsRunning(bool isRunning) { Logger::mIsRunning = isRunning; }

    void threadExec();

    void setWriteBehavior(Log::Output out);

    Log createLog(std::string_view content, Log::LogLevel level = Log::LogLevel::Debug,
                  Log::Output out = Log::Output::Console, std::string_view path = "./Log/",
                  const std::source_location &location = std::source_location::current());

private:
    bool mIsRunning{false};
    //策略模式，实现算法替换
    std::unique_ptr<Write> writeBehavior;

    std::mutex mMutex;
    std::deque<Log> mLogs;
    //std::condition_variable mCond;
    std::thread thread;
};

inline
void Logger::startLogThread() {
    setIsRunning(true);
    thread = std::thread(&Logger::threadExec, this);
}

inline
void Logger::stopLogThread() {
    //等待处理全部日志
    while (!mLogs.empty());
    setIsRunning(false);

    //主线程停止线程日志时 等待日志线程结束
    if (thread.joinable())
        thread.join();
}

/**
 * 同步向控制台输出info
 * @param content 输出文本
 */
inline
void syncLogToConsoleWithInfo(std::string_view content) {
    Logger::getIntance().syncLog(content, Log::LogLevel::Info, Log::Output::Console);
}

/**
 * 同步向控制台输出debug
 * @param content 输出文本
 */
inline
void syncLogToConsoleWithDebug(std::string_view content) {
    Logger::getIntance().syncLog(content, Log::LogLevel::Debug, Log::Output::Console);
}

/**
 * 同步向控制台输出warning
 * @param content 输出文本
 */
inline
void syncLogToConsoleWithWarning(std::string_view content) {
    Logger::getIntance().syncLog(content, Log::LogLevel::Warning, Log::Output::Console);
}

/**
 * 同步向控制台输出error
 * @param content 输出文本
 */
inline
void syncLogToConsoleWithError(std::string_view content) {
    Logger::getIntance().syncLog(content, Log::LogLevel::Error, Log::Output::Console);
}

/**
 * 同步向控制台输出fatal
 * @param content 输出文本
 */
inline
void syncLogToConsoleWithFatal(std::string_view content) {
    Logger::getIntance().syncLog(content, Log::LogLevel::Fatal, Log::Output::Console);
}

/**
 * 异步向控制台输出info
 * @param content 输出文本
 */
void asyncLogToConsoleWithInfo(std::string_view content) {
    Logger::getIntance().asyncLog(content, Log::LogLevel::Info, Log::Output::Console);
}

/**
 * 异步向控制台输出debug
 * @param content 输出文本
 */
inline
void asyncLogToConsoleWithDebug(std::string_view content) {
    Logger::getIntance().asyncLog(content, Log::LogLevel::Debug, Log::Output::Console);
}

/**
 * 异步向控制台输出warning
 * @param content 输出文本
 */
inline
void asyncLogToConsoleWithWarning(std::string_view content) {
    Logger::getIntance().asyncLog(content, Log::LogLevel::Warning, Log::Output::Console);
}

/**
 * 异步向控制台输出error
 * @param content 输出文本
 */
inline
void asyncLogToConsoleWithError(std::string_view content) {
    Logger::getIntance().asyncLog(content, Log::LogLevel::Error, Log::Output::Console);
}

/**
 * 异步向控制台输出fatal
 * @param content 输出文本
 */
inline
void asyncLogToConsoleWithFatal(std::string_view content) {
    Logger::getIntance().asyncLog(content, Log::LogLevel::Fatal, Log::Output::Console);
}

/**
 * 同步向文件输出info
 * @param content 输出文本
 */
inline
void syncLogToFileWithInfo(std::string_view content) {
    Logger::getIntance().syncLog(content, Log::LogLevel::Info, Log::Output::File);
}

/**
 * 同步向文件输出debug
 * @param content 输出文本
 */
inline
void syncLogToFileWithDebug(std::string_view content) {
    Logger::getIntance().syncLog(content, Log::LogLevel::Debug, Log::Output::File);
}

/**
 * 同步向文件输出warning
 * @param content 输出文本
 */
inline
void syncLogToFileWithWarning(std::string_view content) {
    Logger::getIntance().syncLog(content, Log::LogLevel::Warning, Log::Output::File);
}

/**
 * 同步向文件输出error
 * @param content 输出文本
 */
inline
void syncLogToFileWithError(std::string_view content) {
    Logger::getIntance().syncLog(content, Log::LogLevel::Error, Log::Output::File);
}

/**
 * 同步向文件输出fatal
 * @param content 输出文本
 */
inline
void syncLogToFileWithFatal(std::string_view content) {
    Logger::getIntance().syncLog(content, Log::LogLevel::Fatal, Log::Output::File);
}

/**
 * 异步向文件输出info
 * @param content 输出文本
 */
inline
void asyncLogToFileWithInfo(std::string_view content) {
    Logger::getIntance().asyncLog(content, Log::LogLevel::Info, Log::Output::File);
}

/**
 * 异步向文件输出debug
 * @param content 输出文本
 */
inline
void asyncLogToFileWithDebug(std::string_view content) {
    Logger::getIntance().asyncLog(content, Log::LogLevel::Debug, Log::Output::File);
}

/**
 * 异步向文件输出warning
 * @param content 输出文本
 */
inline
void asyncLogToFileWithWarning(std::string_view content) {
    Logger::getIntance().asyncLog(content, Log::LogLevel::Warning, Log::Output::File);
}

/**
 * 异步向文件输出error
 * @param content 输出文本
 */
inline
void asyncLogToFileWithError(std::string_view content) {
    Logger::getIntance().asyncLog(content, Log::LogLevel::Error, Log::Output::File);
}

/**
 * 异步向文件输出fatal
 * @param content 输出文本
 */
inline
void asyncLogToFileWithFatal(std::string_view content) {
    Logger::getIntance().asyncLog(content, Log::LogLevel::Fatal, Log::Output::File);
}


#endif //LOGGER_LOGGER_H
